import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;

public class gbnnode{
        
        public static void main(String[] args) throws IOException {
                
                DatagramSocket clientSocket = null;
                
                if(args.length != 5){
                        System.out.println("You must input 5 arguments. Program terminates.");
                        System.exit(0);
                }
                
                try{
                        selfPort = Integer.parseInt(args[0]);
                        peerPort = Integer.parseInt(args[1]);
                        windowSize = Integer.parseInt(args[2]);
                }catch(Exception e){
                        System.out.println("Self/peer port, and/or window size must be an integer. Program terminates.");
                        System.exit(0);
                }
                
                if(args[3].equals("-d")){
                        try{
                                n = Integer.parseInt(args[4]);
                        }catch(Exception e){
                                System.out.println("The value of n must be an integer. Program terminates.");
                                System.exit(0);
                        }
                }
                
                else if(args[3].equals("-p")){
                        try{
                                p = Float.parseFloat(args[4]);
                        }catch(Exception e){
                                System.out.println("The value of p must be a real number. Program terminates.");
                                System.exit(0);
                        }
                }
                
                else{
                        System.out.println("you must specify the way to control the drop of the packets using -d pr -p.");
                        System.exit(0);
                }
                
                try{
                        clientSocket = new DatagramSocket(selfPort);
                        new listen(clientSocket, peerPort, args[3], args[4]);
                }catch(Exception e){
                        System.out.println("Unable to open port "+selfPort+", pelase try another one.");
                        System.exit(0);
                }
                
                while(true){

                        while(true){
                                System.out.print("node>");
                                command = reader.readLine();
                                if(!command.startsWith("send ")){
                                        System.out.println("Your command must start with \"send\", followed by the message.");
                                        continue;
                                }
                                if(command.length()<6){
                                        System.out.println("The message length must be at least 1.");
                                        continue;
                                }
                                break;
                        }
                        
                        message = command.substring(5);
                        
                        for(int i=0;i<message.length();i++){
                                senderBuffer.add(message.charAt(i));
                        }
                        
                       
                        
                        while(base != senderBuffer.size()){
                                if(nextPacketToSend < min(base+windowSize, senderBuffer.size())){
                                        for(int i = nextPacketToSend; i < min(base+windowSize,senderBuffer.size()); i++){
                                                sendPacket(clientSocket, senderBuffer.get(i), i);
                                                nextPacketToSend++;
                                                if(i == base){
                                                	new timer(base);
                                                }
                                        }
                                }
                        }       
                }
        }
        
        private static int min(int i, int j) {
                if (i>j){
                        return j;
                }
                return i;
        }

        private static void sendPacket(DatagramSocket clientSocket, Character c, int i) throws IOException {
                byte[] sendData = new byte[6];
                sendData[5] = (byte)(senderBuffer.get(i) & 0xff);
                sendData[4] = (byte)(senderBuffer.get(i) >> 8 & 0xff);
                sendData[3] = (byte)(i & 0xff);
                sendData[2] = (byte)(i >> 8 & 0xff);
                sendData[1] = (byte)(i >> 16 & 0xff);
                sendData[0] = (byte)(i >> 24 & 0xff);
                
                DatagramPacket SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), peerPort);
                
                System.out.println(currentTime()+"packet"+i+" "+senderBuffer.get(i)+" sent");
                clientSocket.send(SendPacket);
                
                
                
        }
        
        public static String currentTime() {
                String s = String.valueOf(System.currentTimeMillis());
                return "["+s.substring(0, 10)+"."+s.substring(10)+"]";
        }

        public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        public static int selfPort, peerPort, n, windowSize;
        public static int base=0,nextPacketToSend=0;
        public static float p;
        public static String command, message;
        public static boolean allSend = false;
        public static ArrayList<Character> senderBuffer = new ArrayList<Character>();
}